﻿using ApiGateway;
using ApiGateway.Attr;
using HttpApiGateway.FileUp;
using HttpApiGateway.Helper;
using HttpApiGateway.Interface;
using HttpApiGateway.Model;
using RpcHelper;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using System.Threading;

namespace HttpApiGateway.Collect
{
    internal class ApiRouteCollect
    {
        private static readonly ConcurrentDictionary<int, IApiRoute> _RouteApi = new ConcurrentDictionary<int, IApiRoute>();
        private static readonly ConcurrentDictionary<string, int> _MethodMap = new ConcurrentDictionary<string, int>();
        private static int _Id = 0;

        internal static int CreateApiId()
        {
            return Interlocked.Add(ref _Id, 1);
        }
        #region 注册终结点
        private static RouteConfig _RegApi(Type type, IApiModular modular, Action<IRoute> action)
        {
            RouteConfig config = ApiRouteHelper.GetDefRouteConfig(type, modular);
            ApiGatewayService.RegModular(modular.ServiceName, type);
            MethodInfo[] methods = type.GetMethods();
            bool _isAdd = false;
            methods.ForEach(a =>
            {
                if (a.IsPublic && a.DeclaringType == type && a.GetCustomAttribute(ApiPublicDict.ApiMethodIgnore) == null)
                {
                    if (_RegApi(a, config, modular, action).HasValue)
                    {
                        _isAdd = true;
                    }
                }
            });
            if (_isAdd)
            {
                return config;
            }
            return null;
        }
        public static bool RegApi(IApiController api, IApiModular modular, MethodInfo method, RouteSet set, Action<IRoute> action)
        {
            RouteConfig config = _RegApi(modular, method, set, action);
            if (config == null)
            {
                return false;
            }
            api.Install(config);
            return true;
        }
        public static bool RegApi(IApiModular modular, MethodInfo method, RouteSet set, Action<IRoute> action)
        {
            RouteConfig config = _RegApi(modular, method, set, action);
            return config != null;
        }

        private static RouteConfig _RegApi(IApiModular modular, MethodInfo method, RouteSet set, Action<IRoute> action)
        {
            Type type = method.DeclaringType;
            RouteConfig config = ApiRouteHelper.GetDefRouteConfig(type, modular);
            if (set != null)
            {
                if (set.IsAccredit.HasValue)
                {
                    config.IsAccredit = set.IsAccredit.Value;
                    config.Prower = set.Prower;
                }
                if (!set.RoutePath.IsNull())
                {
                    config.Route = new ApiRouteName(set.RoutePath, set.IsRegex);
                }
            }
            ApiGatewayService.RegModular(modular.ServiceName, type);
            int? id = _RegApi(method, config, modular, action);
            if (id.HasValue)
            {
                return config;
            }
            return null;
        }
        public static bool Remove(MethodInfo method)
        {
            string key = ApiRouteHelper.GetMethodKey(method);
            if (!_MethodMap.TryRemove(key, out int id))
            {
                return false;
            }
            else if (_RouteApi.TryRemove(id, out IApiRoute apiRoute))
            {
                apiRoute.Dispose();
                return true;
            }
            return false;
        }
        public static bool RegBlockUpApi(Type type, IApiModular modular, Action<IRoute> action)
        {
            RouteConfig config = ApiRouteHelper.GetDefRouteConfig(type, modular);
            if (config.Route == null || !config.Route.IsPath)
            {
                new ErrorException("gateway.route.config.error")
                {
                    Args = new System.Collections.Generic.Dictionary<string, string>
                    {
                        {"Type",type.FullName },
                        {"ServiceName",modular.ServiceName },
                        { "Route",config.Route==null?"Null":config.Route.Value}
                    }
                }.SaveLog("Gateway");
                return false;
            }
            ApiGatewayService.RegModular(modular.ServiceName, type);
            return _RegBlockUpApi(modular, config, action);
        }
        private static bool _RegBlockUpApi(IApiModular modular, RouteConfig config, Action<IRoute> action)
        {
            ApiModel model = ApiRouteHelper.GetApiParam(config, modular);
            if (_RouteApi.Where(a => a.Value.ApiUri == model.ApiUri).Select(a => a.Key).FirstOrDefault() != 0)
            {
                new ErrorException("gateway.route.repeat", "uri:" + model.ApiUri).SaveLog("Gateway");
                return false;
            }
            Type argType = config.Type.GetProperty("File").PropertyType;
            IHttpApi api = new BlockUpApi(model, new FuncParam
            {
                ParamType = FuncParamType.参数,
                AttrName = "data",
                DataType = argType,
                IsBasicType = false,
                Name = "File",
                ReceiveMethod = "POST"
            });
            IApiRoute route = new ApiRoute(api, model, config, modular);
            if (_RouteApi.TryAdd(route.Id, route))
            {
                route.InitRoute();
                action(route);
                return true;
            }
            return false;
        }
        public static void RegApi(Type type, IApiModular modular, Action<IRoute> action)
        {
            _RegApi(type, modular, action);
        }
        public static void RegApi(Type type, IApiController api, IApiModular modular, Action<IRoute> action)
        {
            RouteConfig config = _RegApi(type, modular, action);
            if (config == null)
            {
                return;
            }
            api.Install(config);
        }

        private static int? _RegApi(MethodInfo method, RouteConfig config, IApiModular modular, Action<IRoute> action)
        {
            string key = ApiRouteHelper.GetMethodKey(method);
            if (_MethodMap.ContainsKey(key))
            {
                return null;
            }
            else if (!ApiRouteHelper.CheckMethod(method))
            {
                new ErrorLog("gateway.route.reg.fail", "网关路由注册失败!", "Gateway")
                {
                    {"method",method.Name },
                    { "source",method.DeclaringType.FullName}
                }.Save();
                return null;
            }
            ApiModel model = ApiRouteHelper.GetApiParam(method, config, modular);
            if (_RouteApi.Where(a => a.Value.ApiUri == model.ApiUri).Select(a => a.Key).FirstOrDefault() != 0)
            {
                new ErrorException("gateway.route.repeat", "uri:" + model.ApiUri).SaveLog("Gateway");
                return null;
            }
            ApiType type = model.ApiType;
            IHttpApi api = ApiRouteHelper.GetApi(model, ref type);
            model.ApiType = type;
            IApiRoute route = new ApiRoute(api, model, config, modular);
            if (_RouteApi.TryAdd(route.Id, route))
            {
                _MethodMap.TryAdd(key, route.Id);
                route.InitRoute();
                action(route);
                return route.Id;
            }
            return null;
        }

        #endregion
    }
}
